package edu.math.chaos.api;

/**
 * Конвертер координат для рисования на экране в мировых координатах.
 *
 * User: ilya
 * Date: 16.11.13
 * Time: 8:46
 */
public class CoordinatesConverter {

	private WorldPoint leftBottom;
	private WorldPoint rightTop;
	private double step;

	private int m;
	private int n;

	/**
	 * @param leftBottom Левая нижняя точка области.
	 * @param rightTop Правая верхняя точка области.
	 * @param step Шаг сетки.
	 */
	public CoordinatesConverter(WorldPoint leftBottom, WorldPoint rightTop, double step) {
		if (leftBottom == null || rightTop == null) {
			throw new RuntimeException(INCORRECT_BOUNDS_ERROR);
		}

		if (leftBottom.getX() >= rightTop.getX() || leftBottom.getY() >= rightTop.getY()) {
			throw new RuntimeException(INCORRECT_BOUNDS_ERROR);
		}

		if (step <= 0) {
			throw new RuntimeException(INCORRECT_STEP_ERROR);
		}

		this.leftBottom = leftBottom;
		this.rightTop = rightTop;
		this.step = step;

		m = (int) Math.round((rightTop.getX() - leftBottom.getX()) / step);
		n = (int) Math.round((rightTop.getY() - leftBottom.getY()) / step);
	}

	/**
	 * Преобразовывает точку в мировых координатах в точку в экранных координатах.
	 * @param worldPoint Точка в мировых координатах.
	 * @return Точка в экранных координатах.
	 */
	public ScreenPoint toScreenPoint(WorldPoint worldPoint) {
		if (worldPoint == null) {
			return null;
		}

		if (worldPoint.getX() < leftBottom.getX() || worldPoint.getX() > rightTop.getX() ||
			worldPoint.getY() < leftBottom.getY() || worldPoint.getY() > rightTop.getY()) {
			throw new RuntimeException(OUT_OF_BOUNDS_ERROR);
		}

		int i = (int) Math.round((worldPoint.getX() - leftBottom.getX()) / step);
		int j = (int) Math.round((rightTop.getY() - worldPoint.getY()) / step);
		if (i > m) {
			i = m;
		}
		if (j > n) {
			j = n;
		}

		return new ScreenPoint(i, j);
	}

	/**
	 * @return Координаты правой нижней точки экрана.
	 */
	public ScreenPoint getEdgeScreenPoint() {
		return new ScreenPoint(m, n);
	}

	private static final String INCORRECT_BOUNDS_ERROR = "Границы области заданы некорректно";
	private static final String INCORRECT_STEP_ERROR = "Шаг сетки должен быть положительным";
	private static final String OUT_OF_BOUNDS_ERROR = "Точка находится за границей области";
}
